Dynamic Segments
Video Summary
A common convention on the web is to embed unique IDs within the URL. For example, on Twitter, the format is twitter.com/[handle]
, where handle
is a unique ID for each user.
No matter what their handle is, we render the same layout, the same components. But the handle is used to pull all of the data we need, to serve as content for that view.
How might we do something like this in Next?
I created my own mini social network, with the following component:
// /src/app/profiles/1/page.jsimport React from 'react';import { Globe } from 'react-feather';
import { getProfileInfo } from '../../../helpers';
async function ProfilePage() { const profile = await getProfileInfo('1');
return ( <main> {/* UI stuff here */} </main> );}
export default ProfilePage;
In a real app, getProfileInfo
would perform a database call. In this app, it's an async function that waits ~500ms and then plucks a value off a JS object.
This is a Server Component, and so none of this JS will run on the client.
As it stands, I've hardcoded two things:
- The page's directory is
/profiles/1
. - We're calling
getProfileInfo
with the string"1"
.
In order to make this work for any profile ID, we'll use a Next feature called Dynamic Segments.
First, I'll update the directory name to [profileId]
:
By adding square brackets, we're telling Next that this is a dynamic segment. Essentially, a catch-all route that will match any string, and capture it in a variable called profileId
.
Then, inside our component, we'll add a params
prop:
async function ProfilePage({ params }) { const profile = await getProfileInfo(params.profileId);
return ( <main> {/* UI stuff here */} </main> );}
Remember, when it comes to page components in Next, we're not the ones rendering them. We haven't added a <ProfilePage />
element anywhere! It's the framework that renders this component for us. And when it does, it includes some helpful props.
params
is an object that collects all dynamic segments. If we log it out, we'll see:
// When visiting localhost:3001/profiles/josh{ "profileId": "josh"}
We can have as many dynamic segments as we want. For example, I can add another subdirectory:
Now I can visit /profiles/josh/happy
, and our params
object will collect both key/value pairs:
{ "profileId": "josh", "mood": "happy"}
Finally, we can also access query params using the searchParams
prop:
async function ProfilePage({ params, searchParams,}) { const profile = await getProfileInfo(params.profileId);
return ( <main> {/* UI stuff here */} </main> );}
When we visit /profiles/josh?campaign=halloween
, for example, searchParams
will contain this query parameter:
{ "campaign": "halloween",}
Being able to access route and query params is a critical part of any full-stack web framework. I've seen many, many different implementations, across frameworks and languages. And I have to say, I think Next's solution is my favourite. It's incredibly powerful, while also being quite straightforward and relatively easy to understand.
As I mentioned, the Next routing rabbit hole goes deep, but even if you never learn anything else about routing in Next, we've covered enough that you can build some really cool stuff!
The code from this video can be found on Github:
You can also learn more about Dynamic Segments in the Next.js documentation (opens in new tab).